package com.zdlyh.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zdlyh.constants.SystemConstants;
import com.zdlyh.domain.ResponseResult;
import com.zdlyh.domain.dto.AddArticleDto;
import com.zdlyh.domain.dto.ArticleDto;
import com.zdlyh.domain.entity.Article;
import com.zdlyh.domain.entity.ArticleTag;
import com.zdlyh.domain.entity.Category;
import com.zdlyh.service.ArticleService;
import com.zdlyh.mapper.ArticleMapper;
import com.zdlyh.service.ArticleTagService;
import com.zdlyh.service.CategoryService;
import com.zdlyh.utils.BeanCopyUtils;
import com.zdlyh.utils.RedisCache;
import com.zdlyh.domain.vo.*;
import com.zdlyh.utils.RunTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService{
    @Autowired
    private CategoryService categoryService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ArticleTagService articleTagService;

    @Autowired
    private RunTask runTask;

    @Override
    public ResponseResult hotArticleList() {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        // 条件：状态是已发布，浏览量排序前十条
        queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL)
                .orderByDesc(Article::getViewCount)
                        .last("limit 10");
        /*Page<Article> page = new Page<>(1,10);
        page(page,queryWrapper);
        List<Article> articleList = page.getRecords();*/
        List<Article> articleList = baseMapper.selectList(queryWrapper);
        // 从redis中读取viewCount
        for (Article article : articleList) {
            Integer viewCount = redisCache.getCacheMapValue(SystemConstants.article_viewCount, article.getId().toString());
            article.setViewCount(viewCount.longValue());
        }

        List<HotArticleVo> articleVos = BeanCopyUtils.copyBeanList(articleList, HotArticleVo.class);
        return ResponseResult.okResult(articleVos);
    }

    @Override
    public ResponseResult newArticleList() {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        // 条件：状态是已发布，创建时间排序为前五
        queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL)
                .orderByDesc(Article::getCreateTime)
                .last("LIMIT 3");
        List<Article> articleList = baseMapper.selectList(queryWrapper);
        List<NewArticleVo> articleVos = BeanCopyUtils.copyBeanList(articleList, NewArticleVo.class);
        return ResponseResult.okResult(articleVos);
    }

    @Override
    public ResponseResult websiteInfo() {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
        Integer count = baseMapper.selectCount(queryWrapper);

        Long viewTotal = baseMapper.getViewCount();
        WebsiteInfoVo websiteInfoVo = new WebsiteInfoVo(count, viewTotal);
        return ResponseResult.okResult(websiteInfoVo);
    }

    @Override
    public ResponseResult getArticleList(Long categoryId,String title) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        // 状态为发布的文章
        queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL)
                // 有categoryId就传，没有就不传
                .eq(Objects.nonNull(categoryId)&&categoryId>0,Article::getCategoryId,categoryId)
                // 有title就传，没有就不传
                .like(Objects.nonNull(title),Article::getTitle,title)
                // 根据置顶降序
                .orderByDesc(Article::getIsTop);

        List<Article> articleList = baseMapper.selectList(queryWrapper);

        for (Article article : articleList) {
            Category category = categoryService.getById(article.getCategoryId());
            article.setCategoryName(category.getName());
            // 从redis中读取viewCount
            Integer viewCount = redisCache.getCacheMapValue(SystemConstants.article_viewCount, article.getId().toString());

            // 如果在Redis中查不到文章浏览量，那就重新调用一遍启动任务把Mysql的数据同步到Redis中
            if (Objects.isNull(viewCount)){
                try {
                    runTask.updateViewCount();
                }catch (Exception e){
                    e.printStackTrace();
                }
                viewCount = redisCache.getCacheMapValue(SystemConstants.article_viewCount, article.getId().toString());
            }

            article.setViewCount(viewCount.longValue());
        }

        List<ArticleListVo> articleListVos = BeanCopyUtils.copyBeanList(articleList, ArticleListVo.class);

        return ResponseResult.okResult(new PageVo(articleListVos, (long) articleListVos.size()));
    }

    @Override
    public ResponseResult getArticleDetails(Long id) {
        Article article = getById(id);
        // 从redis中读取viewCount
        Integer viewCount = redisCache.getCacheMapValue(SystemConstants.article_viewCount, id.toString());
        article.setViewCount(viewCount.longValue());
        ArticleDetailVo articleDetailVo = BeanCopyUtils.copyBean(article, ArticleDetailVo.class);
        // 根据分类id查出分类name，在set给articleDetailVo
        Category category = categoryService.getById(article.getCategoryId());
        articleDetailVo.setCategoryName(category.getName());
        return ResponseResult.okResult(articleDetailVo);
    }

    @Override
    public ResponseResult updateViewCount(Long id) {
        // 更新redis中对应id的viewCount
        redisCache.incrementCacheMapValue(SystemConstants.article_viewCount,id.toString(),1);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult<PageVo> getArticleList1(Integer pageNum, Integer pageSize, ArticleDto articleDto) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.hasText(articleDto.getTitle()),Article::getTitle,articleDto.getTitle())
                .like(StringUtils.hasText(articleDto.getSummary()),Article::getSummary,articleDto.getSummary());
        Page<Article> page = new Page<>(pageNum,pageSize);
        List<Article> articleList = baseMapper.selectPage(page, queryWrapper).getRecords();

        List<ArticleVo> articleVos = BeanCopyUtils.copyBeanList(articleList, ArticleVo.class);
        PageVo pageVo = new PageVo(articleVos, page.getTotal());
        return ResponseResult.okResult(pageVo);
    }

    @Override
    @Transactional
    public ResponseResult addArticle(AddArticleDto addArticleDto) {
        Article article = BeanCopyUtils.copyBean(addArticleDto, Article.class);
        article.setViewCount(0L);
        baseMapper.insert(article);

        List<ArticleTag> articleTags = addArticleDto.getTags().stream()
                .map(tagId -> new ArticleTag(article.getId(), tagId))
                .collect(Collectors.toList());

        // 添加博客标签关联表，一对多
        articleTagService.saveBatch(articleTags);

        // 更新redis中的文章浏览量
        updateArticleViewCount();
        return ResponseResult.okResult();
    }

    public void updateArticleViewCount(){
        List<Article> articles = baseMapper.selectList(null);
        Map<String, Integer> viewCountMap = articles.stream()
                .collect(Collectors.toMap(article -> article.getId().toString(), article -> article.getViewCount().intValue()));
        // 存储到redis中
        redisCache.setCacheMap(SystemConstants.article_viewCount,viewCountMap);
    }

    @Override
    public ResponseResult getArticleById(Long id) {
        Article article = baseMapper.selectById(id);
        ArticleVo articleVo = BeanCopyUtils.copyBean(article, ArticleVo.class);
        return ResponseResult.okResult(articleVo);
    }

    @Override
    public ResponseResult updateArticle(AddArticleDto addArticleDto) {
        Article article = BeanCopyUtils.copyBean(addArticleDto, Article.class);
        baseMapper.updateById(article);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult deleteArticleById(Long id) {
        baseMapper.deleteById(id);
        return ResponseResult.okResult();
    }
}




